package vn.nghi.common;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class DateTimeUtils {
	
	/**
	 * Trong mot to lich hinh ma tran 6x7. O dau tien duoc danh so la 0
	 * @param strDate Ngay can xac dinh vi tri
	 * @return tra ve vi tri dung cua ngay trong ma tran
	 */
	public static int getIndexOfDayInMonth( String strDate, String dateFormat ) {
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat sdf = new SimpleDateFormat( dateFormat );
		int idx = 0;	
		
		try {
			Date fromDate = sdf.parse( strDate );
			
			// lay ngay 
			calendar.setTime( fromDate );
			idx = calendar.get( Calendar.DAY_OF_MONTH );
			
			// lay vi tri cua ngay dau tien cua thang
			calendar.set( Calendar.DAY_OF_MONTH, 1 );
			int firstDayOfMonth = calendar.get( Calendar.DAY_OF_WEEK );
			
			// set vi tri cua ngay 
			idx = idx + firstDayOfMonth - 2;
		} catch ( ParseException e ) {
			e.printStackTrace();
		}
		return idx;
	}
	
	/**
	 * Trong mot to lich hinh ma tran 7x6. O dau tien duoc danh so la 0
	 * @param currentMonth
	 * @param date
	 * @return
	 */
	public static int getIndexOfDayInMonth( int currentMonth, Date date ) {
		
		Calendar calendar = Calendar.getInstance();
		
		int idx = 0;
		
		// set ngay 
		calendar.setTime( date );

		// Lay ngay dang theo doi
		idx = calendar.get( Calendar.DAY_OF_MONTH );
		
		// Lay thang dang theo doi
		int activeMonth = calendar.get( Calendar.MONTH );

		// lay vi tri cua ngay dau tien cua thang hien tai
		calendar.set( Calendar.MONTH, currentMonth );
		calendar.set( Calendar.DAY_OF_MONTH, 1 );
		int firstDayOfMonth = calendar.get( Calendar.DAY_OF_WEEK );

		// set vi tri cua ngay 
		if ( activeMonth < currentMonth ) {
			calendar.set( Calendar.MONTH, currentMonth - 1 );
			int lastDayOfPreviousMonth = calendar
					.getActualMaximum( Calendar.DAY_OF_MONTH );

			idx = firstDayOfMonth - ( lastDayOfPreviousMonth - idx ) - 2;
		} else if ( activeMonth == currentMonth ) {
			idx = idx + firstDayOfMonth - 2;
		} else if ( activeMonth > currentMonth ) {
			int lastDayOfCurrentMonth = calendar
					.getActualMaximum( Calendar.DAY_OF_MONTH );

			idx = firstDayOfMonth + lastDayOfCurrentMonth + idx - 2;
		}
		
		return idx;
	}
	
	/**
	 * Trong mot to lich hinh ma tran 7x6. O dau tien duoc danh so la 0
	 * @param currentMonth
	 * @param strDate Ngay can xac dinh vi tri
	 * @param dateFormat
	 * @return tra ve vi tri dung cua ngay trong ma tran
	 * @throws ParseException 
	 */
	public static int getIndexOfDayInMonth( int currentMonth, String strDate,
			String dateFormat ) throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat( dateFormat );

		Date fromDate = sdf.parse( strDate );
		
		return getIndexOfDayInMonth( currentMonth, fromDate );
	}
	
	/**
	 * @param strDate
	 * @param originFormat strDate's date format
	 * @param targetFormat the date forma
	 * @return formated date ( empty if the format of strDate is not originFormat ) 
	 * @throws ParseException 
	 */
	public static String convertToAnotherDateFormat( String strDate, String originFormat, String targetFormat ) throws ParseException {
		SimpleDateFormat sdf1 = new SimpleDateFormat( originFormat );
		SimpleDateFormat sdf2 = new SimpleDateFormat( targetFormat );
		
		Date date = sdf1.parse(strDate);

		return sdf2.format(date);
	}
	
	/**
	 * Combine date from year, month, date to specificated format
	 * @param year
	 * @param month
	 * @param day
	 * @param format
	 * @return String of formated Date
	 */
	public static String combineDate( int year, int month, int day, String format ) {
		SimpleDateFormat sdf = new SimpleDateFormat( format );
		
		Calendar cal = Calendar.getInstance();
		cal.set( Calendar.YEAR, year );
		cal.set( Calendar.MONTH, month );
		cal.set( Calendar.DAY_OF_MONTH, day );

		return sdf.format( cal.getTime() );
	}
	
	/**
	 * Combine date from year, month, date to specificated format
	 * @param year
	 * @param month
	 * @param day
	 * @param format
	 * @return
	 */
	public static String combineDate( String year, String month, String day, String format ) {
		int iYear = Integer.parseInt( year );
		int iMonth = Integer.parseInt( month );
		int iDay = Integer.parseInt( day );
		
		return combineDate( iYear, iMonth - 1, iDay, format );
	}	

	/**
	 * 当日か判定します。
	 * 
	 * @param year 年
	 * @param month 月
	 * @param day 日
	 * @return 判定結果（当日の場合true）
	 */
	public static boolean isToday( int year, int month, int day ) {
		Calendar today = Calendar.getInstance();
		int todayYear = today.get( Calendar.YEAR );
		int todayMonth = today.get( Calendar.MONTH ) ;
		int todayDay = today.get( Calendar.DATE );

		return todayYear == year && todayMonth == month && todayDay == day;
	}
	
	public static final String DATE_FORMAT = "yyyy/MM/dd";

	/**
	 * Get the number of days between two specificated day
	 * @param fromDay
	 * @param toDay
	 * @param format Date time format of parameter fromDay and toDay2
	 * @return the number of days between two specificated day
	 * @throws ParseException if format not match with parameter fromDay or toDay
	 */
	public static int getNumOfDay( String fromDay, String toDay, String format ) throws ParseException{
		SimpleDateFormat sdf = new SimpleDateFormat( DATE_FORMAT );
		
		String sFromDay = convertToAnotherDateFormat( fromDay, format, DATE_FORMAT );
		String sToDay = convertToAnotherDateFormat( toDay, format, DATE_FORMAT );
		
		int gap = 0;
		Date dFromDate = sdf.parse( sFromDay );
		Date dToDate = sdf.parse( sToDay );
		gap = daysBetween( dFromDate, dToDate );
		
		return gap + 1;
	}
	
	/**
	 * Get the number of days between two specificated day
	 * @param d1
	 * @param d2
	 * @return the number of days between two specificated day
	 */
	public static int daysBetween( Date d1, Date d2 ){
		return (int)( (d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24));
	}
	
	/**
	 * Combine the date value of date1 and time value of date2
	 * @param date1
	 * @param date2
	 * @param format Date time format of parameter date1 and date 2
	 * @return
	 * @throws ParseException if format not match with parameter date1 or date2
	 */
	public static String combineThisDateAndThatTime( String date1, String date2, String format ) throws ParseException {
		
		SimpleDateFormat sdf = new SimpleDateFormat( format );
		Date dDate1 = sdf.parse( date1 );
		Date dDate2 = sdf.parse( date2 );
		
		Calendar calendar = Calendar.getInstance();
		calendar.setTime( dDate2 );
		
		int hour = calendar.get( Calendar.HOUR_OF_DAY );
		int minute = calendar.get( Calendar.MINUTE );
		
		calendar.setTime( dDate1 );
		calendar.set( Calendar.HOUR_OF_DAY, hour );
		calendar.set( Calendar.MINUTE, minute );
		
		return sdf.format( calendar.getTime() );
	}
	
	/**
	 * Cong vao mot so ngay xac dinh 
	 * @param date String type
	 * @param format Date time format of parameter date
	 * @param num
	 * @return
	 * @throws ParseException if format not match with parameter date
	 */
	public static String addDate( String date, String format, int num ) throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat( format );
		
		Date dDate = sdf.parse( date );
		Calendar calendar = Calendar.getInstance();
		calendar.setTime( dDate );
		
		calendar.add( Calendar.DAY_OF_YEAR, num );
		
		return sdf.format( calendar.getTime() );
	}
   
	protected List<ScheduleDateLable> getDateLabelForCalendar(Date startDate,
			Date endDate) {
		int duration = (int) dayBetween(startDate, endDate);

		return getDateLabelForCalendar(startDate, duration);
	}

 	protected double dayBetween(Date startDate, Date endDate) {

		long l = (endDate.getTime() - startDate.getTime()) / 86400;

		double kq = (double) l / 1000;

		return kq;

	}
   
   /**
	 * カレンダーの日付ラベルを取得処理
	 *
	 * @param startDate カレンダーに最初の日
	 * @param duration カレンダーの表示する範囲
	 * @return　カレンダーの日付ラベルリスト
	 */
	public static List<ScheduleDateLable> getDateLabelForCalendar(Date startDate,
			int duration) {
		List<ScheduleDateLable> scheduleDateLabelList = new ArrayList<ScheduleDateLable>();

		Calendar cal = Calendar.getInstance();
		cal.setTime(startDate);

		Map<Integer, String> dateNameMap = createDateNameMap();

		ScheduleDateLable dayItem;
		for (int i = 0; i < duration; i++) {
			dayItem = new ScheduleCommon.ScheduleDateLable();

			StringBuilder labelBuilder = new StringBuilder();

			// 次の月になったら"MM/1"のように表示する
			if (cal.get(Calendar.DAY_OF_MONTH) == 1) {
				labelBuilder.append(cal.get(Calendar.MONTH) + 1).append("/");
			}

			labelBuilder.append(cal.get(Calendar.DAY_OF_MONTH)).append("(")
					.append(dateNameMap.get(cal.get(Calendar.DAY_OF_WEEK)))
					.append(")");

			dayItem.dateLabel = labelBuilder.toString();

			// CSSクラスを指定する
			if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
				dayItem.className = "sun";
			} else if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
				dayItem.className = "blue sat";
			} else {
				dayItem.className = "yellow";
			}

			scheduleDateLabelList.add(dayItem);
			cal.add(Calendar.DAY_OF_YEAR, 1);
		}

		return scheduleDateLabelList;
	}


	/**
	 * CalendarのDAY_OF_WEEKフィールドとラベルをペアーにする
	 *
	 * @return　CalendarのDAY_OF_WEEKフィールドとラベルのマップ型
	 */
	private static  Map<Integer, String> createDateNameMap() {
		Map<Integer, String> map = new HashMap<Integer, String>();

		map.put(Calendar.SUNDAY, "日");
		map.put(Calendar.MONTH, "月");
		map.put(Calendar.TUESDAY, "火");
		map.put(Calendar.WEDNESDAY, "水");
		map.put(Calendar.THURSDAY, "木");
		map.put(Calendar.FRIDAY, "金");
		map.put(Calendar.SATURDAY, "土");

		return map;
	}
}
